import sys
import os
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                             QLabel, QPushButton, QFileDialog, QSlider, QSpinBox, QComboBox,
                             QTabWidget, QGroupBox, QGridLayout, QSplitter, QMessageBox,
                             QAction, QToolBar, QDockWidget, QListWidget, QLineEdit,
                             QProgressBar, QDoubleSpinBox, QCheckBox, QDialog, QFormLayout)
from PyQt5.QtGui import QPixmap, QImage, QPainter, QPen, QColor, QFont
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QPoint, QRect, QSize


class ImageProcessor:
    """图像处理核心类，封装各种图像处理算法"""

    def __init__(self):
        self.original_image = None
        self.processed_image = None
        self.shapes = []

    def load_image(self, file_path):
        """加载图像"""
        self.original_image = cv2.imread(file_path)
        self.processed_image = self.original_image.copy()
        return self.processed_image

    def rotate_image(self, angle):
        """旋转图像"""
        if self.processed_image is not None:
            (h, w) = self.processed_image.shape[:2]
            center = (w // 2, h // 2)
            M = cv2.getRotationMatrix2D(center, angle, 1.0)
            self.processed_image = cv2.warpAffine(self.processed_image, M, (w, h))
            return self.processed_image
        return None

    def scale_image(self, scale_factor):
        """缩放图像"""
        if self.processed_image is not None:
            width = int(self.processed_image.shape[1] * scale_factor)
            height = int(self.processed_image.shape[0] * scale_factor)
            dim = (width, height)
            self.processed_image = cv2.resize(self.processed_image, dim, interpolation=cv2.INTER_AREA)
            return self.processed_image
        return None

    def crop_image(self, x, y, width, height):
        """裁剪图像"""
        if self.processed_image is not None:
            self.processed_image = self.processed_image[y:y + height, x:x + width]
            return self.processed_image
        return None

    def adjust_brightness_contrast(self, brightness=0, contrast=1.0):
        """调整亮度和对比度"""
        if self.processed_image is not None:
            self.processed_image = cv2.convertScaleAbs(self.processed_image, alpha=contrast, beta=brightness)
            return self.processed_image
        return None

    def adjust_saturation(self, value):
        """调整饱和度"""
        if self.processed_image is not None:
            hsv = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2HSV)
            h, s, v = cv2.split(hsv)
            s = np.clip(s * value, 0, 255).astype(hsv.dtype)
            hsv = cv2.merge([h, s, v])
            self.processed_image = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
            return self.processed_image
        return None

    def smooth_image(self, kernel_size=5):
        """平滑图像"""
        if self.processed_image is not None:
            self.processed_image = cv2.GaussianBlur(self.processed_image, (kernel_size, kernel_size), 0)
            return self.processed_image
        return None

    def detect_shapes(self):
        """检测图像中的形状"""
        if self.processed_image is not None:
            gray = cv2.cvtColor(self.processed_image, cv2.COLOR_BGR2GRAY)
            _, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
            contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

            self.shapes = []
            for contour in contours:
                epsilon = 0.01 * cv2.arcLength(contour, True)
                approx = cv2.approxPolyDP(contour, epsilon, True)
                x, y, w, h = cv2.boundingRect(approx)

                shape_type = "未识别"
                if len(approx) == 3:
                    shape_type = "三角形"
                elif len(approx) == 4:
                    shape_type = "矩形"
                elif len(approx) > 4:
                    area = cv2.contourArea(contour)
                    hull = cv2.convexHull(contour)
                    hull_area = cv2.contourArea(hull)
                    solidity = float(area) / hull_area

                    if solidity > 0.9:
                        shape_type = "圆形"
                    else:
                        shape_type = "多边形"

                self.shapes.append({
                    'contour': contour,
                    'type': shape_type,
                    'bounding_box': (x, y, w, h)
                })

            return self.shapes
        return []

    def stitch_images(self, images):
        """图像拼接"""
        stitcher = cv2.Stitcher_create()
        status, result = stitcher.stitch(images)

        if status == cv2.Stitcher_OK:
            self.processed_image = result
            return self.processed_image, True
        else:
            return None, False


class VideoThread(QThread):
    """视频处理线程"""
    change_pixmap_signal = pyqtSignal(np.ndarray)

    def __init__(self, processor, detection_type="none"):
        super().__init__()
        self.processor = processor
        self.detection_type = detection_type
        self._run_flag = True

    def run(self):
        # 打开摄像头
        cap = cv2.VideoCapture(0)

        while self._run_flag:
            ret, frame = cap.read()
            if ret:
                processed_frame = frame.copy()

                if self.detection_type == "shape":
                    shapes = self.processor.detect_shapes()

                    for shape in shapes:
                        x, y, w, h = shape['bounding_box']
                        shape_type = shape['type']

                        cv2.rectangle(processed_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
                        cv2.putText(processed_frame, shape_type, (x, y - 10),
                                    cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

                self.change_pixmap_signal.emit(processed_frame)

        # 释放摄像头
        cap.release()

    def stop(self):
        """停止线程"""
        self._run_flag = False
        self.wait()

    def set_detection_type(self, detection_type):
        """设置检测类型"""
        self.detection_type = detection_type


class ImageWidget(QWidget):
    """图像显示控件"""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.image = None
        self.setMinimumSize(1, 1)
        self.drawing = False
        self.start_point = QPoint()
        self.end_point = QPoint()
        self.crop_mode = False

    def set_image(self, image):
        """设置要显示的图像"""
        self.image = image
        self.update()

    def paintEvent(self, event):
        """绘制事件"""
        if self.image:
            painter = QPainter(self)
            painter.drawPixmap(0, 0, self.image.scaled(
                self.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))

            # 绘制裁剪矩形
            if self.crop_mode and self.drawing:
                rect = QRect(self.start_point, self.end_point)
                painter.setPen(QPen(QColor(255, 0, 0), 2, Qt.DashLine))
                painter.drawRect(rect)

    def mousePressEvent(self, event):
        """鼠标按下事件"""
        if self.crop_mode and event.button() == Qt.LeftButton:
            self.drawing = True
            self.start_point = event.pos()
            self.end_point = event.pos()
            self.update()

    def mouseMoveEvent(self, event):
        """鼠标移动事件"""
        if self.crop_mode and self.drawing:
            self.end_point = event.pos()
            self.update()

    def mouseReleaseEvent(self, event):
        """鼠标释放事件"""
        if self.crop_mode and event.button() == Qt.LeftButton:
            self.drawing = False
            self.end_point = event.pos()
            self.update()

    def get_crop_rect(self):
        """获取裁剪区域"""
        if self.crop_mode and not self.drawing:
            rect = QRect(self.start_point, self.end_point).normalized()

            # 转换为图像坐标
            if self.image:
                scale_x = self.image.width() / self.width()
                scale_y = self.image.height() / self.height()

                x = int(rect.x() * scale_x)
                y = int(rect.y() * scale_y)
                width = int(rect.width() * scale_x)
                height = int(rect.height() * scale_y)

                return x, y, width, height

        return None

    def set_crop_mode(self, enabled):
        """设置裁剪模式"""
        self.crop_mode = enabled
        self.drawing = False
        self.start_point = QPoint()
        self.end_point = QPoint()
        self.update()


class MainWindow(QMainWindow):
    """主窗口类"""

    def __init__(self):
        super().__init__()

        self.processor = ImageProcessor()
        self.video_thread = None

        self.init_ui()

    def init_ui(self):
        """初始化用户界面"""
        # 设置窗口标题和大小
        self.setWindowTitle("图像处理平台（无人脸识别）")
        self.setGeometry(100, 100, 1000, 800)

        # 创建中央部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)

        # 创建分割器
        splitter = QSplitter(Qt.Horizontal)
        main_layout.addWidget(splitter)

        # 创建左侧控制面板
        control_panel = QWidget()
        control_layout = QVBoxLayout(control_panel)
        splitter.addWidget(control_panel)

        # 创建选项卡控件
        tab_widget = QTabWidget()
        control_layout.addWidget(tab_widget)

        # 图像处理选项卡
        image_processing_tab = QWidget()
        image_processing_layout = QVBoxLayout(image_processing_tab)

        # 旋转控制
        rotate_group = QGroupBox("旋转")
        rotate_layout = QHBoxLayout()
        rotate_label = QLabel("角度:")
        self.rotate_spinbox = QSpinBox()
        self.rotate_spinbox.setRange(-360, 360)
        self.rotate_spinbox.setValue(0)
        rotate_button = QPushButton("旋转")
        rotate_button.clicked.connect(self.rotate_image)

        rotate_layout.addWidget(rotate_label)
        rotate_layout.addWidget(self.rotate_spinbox)
        rotate_layout.addWidget(rotate_button)
        rotate_group.setLayout(rotate_layout)

        # 缩放控制
        scale_group = QGroupBox("缩放")
        scale_layout = QHBoxLayout()
        scale_label = QLabel("比例:")
        self.scale_spinbox = QDoubleSpinBox()
        self.scale_spinbox.setRange(0.1, 5.0)
        self.scale_spinbox.setValue(1.0)
        self.scale_spinbox.setSingleStep(0.1)
        scale_button = QPushButton("缩放")
        scale_button.clicked.connect(self.scale_image)

        scale_layout.addWidget(scale_label)
        scale_layout.addWidget(self.scale_spinbox)
        scale_layout.addWidget(scale_button)
        scale_group.setLayout(scale_layout)

        # 裁剪控制
        crop_group = QGroupBox("裁剪")
        crop_layout = QHBoxLayout()
        self.crop_button = QPushButton("开始裁剪")
        self.crop_button.clicked.connect(self.toggle_crop_mode)
        self.apply_crop_button = QPushButton("应用裁剪")
        self.apply_crop_button.clicked.connect(self.crop_image)
        self.apply_crop_button.setEnabled(False)

        crop_layout.addWidget(self.crop_button)
        crop_layout.addWidget(self.apply_crop_button)
        crop_group.setLayout(crop_layout)

        # 亮度和对比度控制
        brightness_contrast_group = QGroupBox("亮度和对比度")
        brightness_contrast_layout = QGridLayout()

        brightness_label = QLabel("亮度:")
        self.brightness_slider = QSlider(Qt.Horizontal)
        self.brightness_slider.setRange(-100, 100)
        self.brightness_slider.setValue(0)
        self.brightness_value_label = QLabel("0")

        contrast_label = QLabel("对比度:")
        self.contrast_slider = QSlider(Qt.Horizontal)
        self.contrast_slider.setRange(50, 200)
        self.contrast_slider.setValue(100)
        self.contrast_value_label = QLabel("1.0")

        brightness_apply_button = QPushButton("应用")
        brightness_apply_button.clicked.connect(self.adjust_brightness_contrast)

        brightness_contrast_layout.addWidget(brightness_label, 0, 0)
        brightness_contrast_layout.addWidget(self.brightness_slider, 0, 1)
        brightness_contrast_layout.addWidget(self.brightness_value_label, 0, 2)

        brightness_contrast_layout.addWidget(contrast_label, 1, 0)
        brightness_contrast_layout.addWidget(self.contrast_slider, 1, 1)
        brightness_contrast_layout.addWidget(self.contrast_value_label, 1, 2)

        brightness_contrast_layout.addWidget(brightness_apply_button, 2, 0, 1, 3)

        brightness_contrast_group.setLayout(brightness_contrast_layout)

        # 饱和度控制
        saturation_group = QGroupBox("饱和度")
        saturation_layout = QHBoxLayout()
        saturation_label = QLabel("饱和度:")
        self.saturation_slider = QSlider(Qt.Horizontal)
        self.saturation_slider.setRange(0, 200)
        self.saturation_slider.setValue(100)
        self.saturation_value_label = QLabel("1.0")
        saturation_apply_button = QPushButton("应用")
        saturation_apply_button.clicked.connect(self.adjust_saturation)

        saturation_layout.addWidget(saturation_label)
        saturation_layout.addWidget(self.saturation_slider, 1)
        saturation_layout.addWidget(self.saturation_value_label)
        saturation_layout.addWidget(saturation_apply_button)
        saturation_group.setLayout(saturation_layout)

        # 平滑处理控制
        smooth_group = QGroupBox("平滑处理")
        smooth_layout = QHBoxLayout()
        smooth_label = QLabel("平滑度:")
        self.smooth_spinbox = QSpinBox()
        self.smooth_spinbox.setRange(1, 25)
        self.smooth_spinbox.setValue(5)
        self.smooth_spinbox.setSingleStep(2)
        smooth_button = QPushButton("应用")
        smooth_button.clicked.connect(self.smooth_image)

        smooth_layout.addWidget(smooth_label)
        smooth_layout.addWidget(self.smooth_spinbox)
        smooth_layout.addWidget(smooth_button)
        smooth_group.setLayout(smooth_layout)

        # 添加所有控制组到图像处理选项卡
        image_processing_layout.addWidget(rotate_group)
        image_processing_layout.addWidget(scale_group)
        image_processing_layout.addWidget(crop_group)
        image_processing_layout.addWidget(brightness_contrast_group)
        image_processing_layout.addWidget(saturation_group)
        image_processing_layout.addWidget(smooth_group)
        image_processing_layout.addStretch()

        tab_widget.addTab(image_processing_tab, "图像处理")

        # 计算机视觉选项卡
        cv_tab = QWidget()
        cv_layout = QVBoxLayout(cv_tab)

        # 形状识别控制
        shape_detection_group = QGroupBox("形状识别")
        shape_detection_layout = QHBoxLayout()
        self.shape_detection_button = QPushButton("检测形状")
        self.shape_detection_button.clicked.connect(self.detect_shapes)

        shape_detection_layout.addWidget(self.shape_detection_button)
        shape_detection_group.setLayout(shape_detection_layout)

        # 图像拼接控制
        stitch_group = QGroupBox("图像拼接")
        stitch_layout = QVBoxLayout()

        self.stitch_image_list = QListWidget()
        add_stitch_image_button = QPushButton("添加图像")
        add_stitch_image_button.clicked.connect(self.add_stitch_image)
        stitch_images_button = QPushButton("拼接图像")
        stitch_images_button.clicked.connect(self.stitch_images)

        stitch_layout.addWidget(self.stitch_image_list)
        stitch_layout.addWidget(add_stitch_image_button)
        stitch_layout.addWidget(stitch_images_button)
        stitch_group.setLayout(stitch_layout)

        cv_layout.addWidget(shape_detection_group)
        cv_layout.addWidget(stitch_group)
        cv_layout.addStretch()

        tab_widget.addTab(cv_tab, "计算机视觉")

        # 视频处理选项卡
        video_tab = QWidget()
        video_layout = QVBoxLayout(video_tab)

        # 视频播放控制
        video_playback_group = QGroupBox("视频播放")
        video_playback_layout = QVBoxLayout()

        self.video_path_input = QLineEdit()
        browse_video_button = QPushButton("浏览视频...")
        browse_video_button.clicked.connect(self.browse_video)

        video_controls_layout = QHBoxLayout()
        self.play_button = QPushButton("播放")
        self.pause_button = QPushButton("暂停")
        self.stop_button = QPushButton("停止")

        self.play_button.clicked.connect(self.play_video)
        self.pause_button.clicked.connect(self.pause_video)
        self.stop_button.clicked.connect(self.stop_video)

        self.pause_button.setEnabled(False)
        self.stop_button.setEnabled(False)

        video_controls_layout.addWidget(self.play_button)
        video_controls_layout.addWidget(self.pause_button)
        video_controls_layout.addWidget(self.stop_button)

        video_playback_layout.addWidget(self.video_path_input)
        video_playback_layout.addWidget(browse_video_button)
        video_playback_layout.addLayout(video_controls_layout)
        video_playback_group.setLayout(video_playback_layout)

        # 实时视频处理控制
        realtime_video_group = QGroupBox("实时视频处理")
        realtime_video_layout = QVBoxLayout()

        self.start_camera_button = QPushButton("开启摄像头")
        self.start_camera_button.clicked.connect(self.start_camera)

        detection_type_layout = QHBoxLayout()
        detection_type_label = QLabel("检测类型:")
        self.detection_type_combo = QComboBox()
        self.detection_type_combo.addItems(["无", "形状"])
        self.detection_type_combo.currentIndexChanged.connect(self.change_detection_type)

        detection_type_layout.addWidget(detection_type_label)
        detection_type_layout.addWidget(self.detection_type_combo)

        self.stop_camera_button = QPushButton("关闭摄像头")
        self.stop_camera_button.clicked.connect(self.stop_camera)
        self.stop_camera_button.setEnabled(False)

        realtime_video_layout.addWidget(self.start_camera_button)
        realtime_video_layout.addLayout(detection_type_layout)
        realtime_video_layout.addWidget(self.stop_camera_button)
        realtime_video_group.setLayout(realtime_video_layout)

        video_layout.addWidget(video_playback_group)
        video_layout.addWidget(realtime_video_group)
        video_layout.addStretch()

        tab_widget.addTab(video_tab, "视频处理")

        # 创建右侧图像显示区域
        display_widget = QWidget()
        display_layout = QVBoxLayout(display_widget)
        splitter.addWidget(display_widget)

        # 图像显示控件
        self.image_display = ImageWidget()
        display_layout.addWidget(self.image_display, 1)

        # 状态栏
        self.statusBar().showMessage("就绪")

        # 创建菜单栏
        menubar = self.menuBar()

        # 文件菜单
        file_menu = menubar.addMenu("文件")

        # 打开文件动作
        open_action = QAction("打开", self)
        open_action.setShortcut("Ctrl+O")
        open_action.triggered.connect(self.open_file)
        file_menu.addAction(open_action)

        # 保存文件动作
        save_action = QAction("保存", self)
        save_action.setShortcut("Ctrl+S")
        save_action.triggered.connect(self.save_file)
        file_menu.addAction(save_action)

        # 退出动作
        exit_action = QAction("退出", self)
        exit_action.setShortcut("Ctrl+Q")
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

        # 编辑菜单
        edit_menu = menubar.addMenu("编辑")

        # 撤销动作
        undo_action = QAction("撤销", self)
        undo_action.setShortcut("Ctrl+Z")
        undo_action.triggered.connect(self.undo)
        edit_menu.addAction(undo_action)

        # 图像处理菜单
        image_menu = menubar.addMenu("图像处理")

        # 旋转动作
        rotate_action = QAction("旋转", self)
        rotate_action.triggered.connect(self.rotate_image)
        image_menu.addAction(rotate_action)

        # 缩放动作
        scale_action = QAction("缩放", self)
        scale_action.triggered.connect(self.scale_image)
        image_menu.addAction(scale_action)

        # 裁剪动作
        crop_action = QAction("裁剪", self)
        crop_action.triggered.connect(self.toggle_crop_mode)
        image_menu.addAction(crop_action)

        # 计算机视觉菜单
        cv_menu = menubar.addMenu("计算机视觉")

        # 形状识别动作
        shape_detection_action = QAction("形状识别", self)
        shape_detection_action.triggered.connect(self.detect_shapes)
        cv_menu.addAction(shape_detection_action)

        # 视频菜单
        video_menu = menubar.addMenu("视频")

        # 打开视频动作
        open_video_action = QAction("打开视频", self)
        open_video_action.triggered.connect(self.browse_video)
        video_menu.addAction(open_video_action)

        # 播放视频动作
        play_video_action = QAction("播放", self)
        play_video_action.triggered.connect(self.play_video)
        video_menu.addAction(play_video_action)

        # 打开摄像头动作
        start_camera_action = QAction("开启摄像头", self)
        start_camera_action.triggered.connect(self.start_camera)
        video_menu.addAction(start_camera_action)

        # 创建工具栏
        toolbar = QToolBar("工具栏")
        self.addToolBar(toolbar)

        # 添加工具按钮
        toolbar.addAction(open_action)
        toolbar.addAction(save_action)
        toolbar.addSeparator()
        toolbar.addAction(rotate_action)
        toolbar.addAction(scale_action)
        toolbar.addAction(crop_action)
        toolbar.addSeparator()
        toolbar.addAction(shape_detection_action)
        toolbar.addSeparator()
        toolbar.addAction(open_video_action)
        toolbar.addAction(play_video_action)
        toolbar.addAction(start_camera_action)

        # 设置分割器初始大小
        splitter.setSizes([300, 700])

        # 连接信号和槽
        self.brightness_slider.valueChanged.connect(
            lambda: self.brightness_value_label.setText(str(self.brightness_slider.value())))
        self.contrast_slider.valueChanged.connect(
            lambda: self.contrast_value_label.setText(f"{self.contrast_slider.value() / 100:.1f}"))
        self.saturation_slider.valueChanged.connect(
            lambda: self.saturation_value_label.setText(f"{self.saturation_slider.value() / 100:.1f}"))

    def open_file(self):
        """打开文件对话框"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp *.gif)")

        if file_path:
            self.load_image(file_path)

    def load_image(self, file_path):
        """加载图像并显示"""
        try:
            # 使用处理器加载图像
            image = self.processor.load_image(file_path)

            if image is not None:
                # 转换为Qt格式
                height, width, channel = image.shape
                bytes_per_line = 3 * width
                q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format_BGR888)
                pixmap = QPixmap.fromImage(q_img)

                # 显示图像
                self.image_display.set_image(pixmap)
                self.statusBar().showMessage(f"已加载图像: {os.path.basename(file_path)}")
            else:
                self.statusBar().showMessage("无法加载图像")

        except Exception as e:
            QMessageBox.critical(self, "错误", f"加载图像时出错: {str(e)}")
            self.statusBar().showMessage("加载图像失败")

    def save_file(self):
        """保存文件对话框"""
        if self.processor.processed_image is not None:
            file_path, _ = QFileDialog.getSaveFileName(
                self, "保存图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)")

            if file_path:
                try:
                    # 保存图像
                    cv2.imwrite(file_path, self.processor.processed_image)
                    self.statusBar().showMessage(f"已保存图像: {os.path.basename(file_path)}")
                except Exception as e:
                    QMessageBox.critical(self, "错误", f"保存图像时出错: {str(e)}")
                    self.statusBar().showMessage("保存图像失败")
        else:
            QMessageBox.warning(self, "警告", "没有可保存的图像")

    def undo(self):
        """撤销操作"""
        if self.processor.original_image is not None:
            self.processor.processed_image = self.processor.original_image.copy()
            self.update_image_display()
            self.statusBar().showMessage("已撤销操作")

    def rotate_image(self):
        """旋转图像"""
        if self.processor.processed_image is not None:
            angle = self.rotate_spinbox.value()
            self.processor.rotate_image(angle)
            self.update_image_display()
            self.statusBar().showMessage(f"图像已旋转 {angle} 度")

    def scale_image(self):
        """缩放图像"""
        if self.processor.processed_image is not None:
            scale_factor = self.scale_spinbox.value()
            self.processor.scale_image(scale_factor)
            self.update_image_display()
            self.statusBar().showMessage(f"图像已缩放 {scale_factor * 100}%")

    def toggle_crop_mode(self):
        """切换裁剪模式"""
        if self.processor.processed_image is not None:
            current_mode = self.image_display.crop_mode
            self.image_display.set_crop_mode(not current_mode)

            if not current_mode:
                self.crop_button.setText("取消裁剪")
                self.apply_crop_button.setEnabled(True)
                self.statusBar().showMessage("裁剪模式已启用")
            else:
                self.crop_button.setText("开始裁剪")
                self.apply_crop_button.setEnabled(False)
                self.statusBar().showMessage("裁剪模式已禁用")

    def crop_image(self):
        """裁剪图像"""
        if self.processor.processed_image is not None:
            crop_rect = self.image_display.get_crop_rect()
            if crop_rect:
                x, y, width, height = crop_rect
                self.processor.crop_image(x, y, width, height)
                self.image_display.set_crop_mode(False)
                self.crop_button.setText("开始裁剪")
                self.apply_crop_button.setEnabled(False)
                self.update_image_display()
                self.statusBar().showMessage("图像已裁剪")
            else:
                QMessageBox.warning(self, "警告", "请先选择裁剪区域")

    def adjust_brightness_contrast(self):
        """调整亮度和对比度"""
        if self.processor.processed_image is not None:
            brightness = self.brightness_slider.value()
            contrast = self.contrast_slider.value() / 100.0
            self.processor.adjust_brightness_contrast(brightness, contrast)
            self.update_image_display()
            self.statusBar().showMessage(f"亮度和对比度已调整")

    def adjust_saturation(self):
        """调整饱和度"""
        if self.processor.processed_image is not None:
            saturation = self.saturation_slider.value() / 100.0
            self.processor.adjust_saturation(saturation)
            self.update_image_display()
            self.statusBar().showMessage(f"饱和度已调整")

    def smooth_image(self):
        """平滑图像"""
        if self.processor.processed_image is not None:
            kernel_size = self.smooth_spinbox.value()
            if kernel_size % 2 == 0:
                kernel_size += 1  # 确保核大小为奇数
                self.smooth_spinbox.setValue(kernel_size)

            self.processor.smooth_image(kernel_size)
            self.update_image_display()
            self.statusBar().showMessage(f"图像已平滑处理")

    def detect_shapes(self):
        """检测图像中的形状"""
        if self.processor.processed_image is not None:
            shapes = self.processor.detect_shapes()

            # 创建结果图像
            result_image = self.processor.processed_image.copy()

            for shape in shapes:
                x, y, w, h = shape['bounding_box']
                shape_type = shape['type']

                cv2.rectangle(result_image, (x, y), (x + w, y + h), (0, 255, 0), 2)
                cv2.putText(result_image, shape_type, (x, y - 10),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)

            # 更新显示
            self.processor.processed_image = result_image
            self.update_image_display()

            # 显示结果
            self.statusBar().showMessage(f"已检测到 {len(shapes)} 个形状")

    def add_stitch_image(self):
        """添加要拼接的图像"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)")

        if file_path:
            self.stitch_image_list.addItem(file_path)
            self.statusBar().showMessage(f"已添加图像: {os.path.basename(file_path)}")

    def stitch_images(self):
        """拼接图像"""
        if self.stitch_image_list.count() < 2:
            QMessageBox.warning(self, "警告", "至少需要选择两张图像进行拼接")
            return

        images = []
        for i in range(self.stitch_image_list.count()):
            file_path = self.stitch_image_list.item(i).text()
            image = cv2.imread(file_path)
            if image is not None:
                images.append(image)

        if len(images) < 2:
            QMessageBox.warning(self, "警告", "无法加载足够的图像进行拼接")
            return

        # 显示进度条
        progress_dialog = QMessageBox(self)
        progress_dialog.setWindowTitle("正在拼接图像")
        progress_dialog.setText("请稍候...")
        progress_dialog.setStandardButtons(QMessageBox.NoButton)
        progress_dialog.show()

        # 执行拼接
        result, success = self.processor.stitch_images(images)

        progress_dialog.close()

        if success:
            self.update_image_display()
            self.statusBar().showMessage("图像拼接成功")
        else:
            QMessageBox.warning(self, "警告", "图像拼接失败")
            self.statusBar().showMessage("图像拼接失败")

    def browse_video(self):
        """浏览视频文件"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "打开视频", "", "视频文件 (*.mp4 *.avi *.mov *.mkv)")

        if file_path:
            self.video_path_input.setText(file_path)
            self.statusBar().showMessage(f"已选择视频: {os.path.basename(file_path)}")

    def play_video(self):
        """播放视频"""
        video_path = self.video_path_input.text()

        if not video_path or not os.path.exists(video_path):
            QMessageBox.warning(self, "警告", "请选择有效的视频文件")
            return

        # 这里只是简单显示视频路径，实际应用中需要实现视频播放功能
        self.statusBar().showMessage(f"正在播放视频: {os.path.basename(video_path)}")

        # 更新按钮状态
        self.play_button.setEnabled(False)
        self.pause_button.setEnabled(True)
        self.stop_button.setEnabled(True)

    def pause_video(self):
        """暂停视频"""
        self.statusBar().showMessage("视频已暂停")

        # 更新按钮状态
        self.play_button.setEnabled(True)
        self.pause_button.setEnabled(False)
        self.stop_button.setEnabled(True)

    def stop_video(self):
        """停止视频"""
        self.statusBar().showMessage("视频已停止")

        # 更新按钮状态
        self.play_button.setEnabled(True)
        self.pause_button.setEnabled(False)
        self.stop_button.setEnabled(False)

    def start_camera(self):
        """开启摄像头"""
        if self.video_thread is None:
            self.video_thread = VideoThread(self.processor)
            self.video_thread.change_pixmap_signal.connect(self.update_camera_display)
            self.video_thread.start()

            # 更新UI状态
            self.start_camera_button.setEnabled(False)
            self.stop_camera_button.setEnabled(True)
            self.statusBar().showMessage("摄像头已开启")

    def stop_camera(self):
        """关闭摄像头"""
        if self.video_thread is not None:
            self.video_thread.stop()
            self.video_thread = None

            # 更新UI状态
            self.start_camera_button.setEnabled(True)
            self.stop_camera_button.setEnabled(False)
            self.statusBar().showMessage("摄像头已关闭")

    def change_detection_type(self, index):
        """更改检测类型"""
        detection_types = ["none", "shape"]
        detection_type = detection_types[index]

        if self.video_thread is not None:
            self.video_thread.set_detection_type(detection_type)
            self.statusBar().showMessage(f"检测类型已更改为: {detection_type}")

    def update_camera_display(self, image):
        """更新摄像头显示"""
        height, width, channel = image.shape
        bytes_per_line = 3 * width
        q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format_BGR888)
        pixmap = QPixmap.fromImage(q_img)
        self.image_display.set_image(pixmap)

    def update_image_display(self):
        """更新图像显示"""
        if self.processor.processed_image is not None:
            height, width, channel = self.processor.processed_image.shape
            bytes_per_line = 3 * width
            q_img = QImage(self.processor.processed_image.data, width, height, bytes_per_line, QImage.Format_BGR888)
            pixmap = QPixmap.fromImage(q_img)
            self.image_display.set_image(pixmap)


if __name__ == "__main__":
    # 设置中文字体
    os.environ["QT_FONT_DPI"] = "96"

    app = QApplication(sys.argv)
    app.setStyle('Fusion')

    # 设置应用程序字体
    font = QFont("SimHei")
    app.setFont(font)

    window = MainWindow()
    window.show()

    sys.exit(app.exec_())